package sbc.group1.lab1.mozartspaces;

import java.io.Serializable;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;

import org.mozartspaces.capi3.Capi3AspectPort;
import org.mozartspaces.capi3.CoordinationData;
import org.mozartspaces.capi3.LabelCoordinator;
import org.mozartspaces.capi3.Selector;
import org.mozartspaces.capi3.SubTransaction;
import org.mozartspaces.capi3.Transaction;
import org.mozartspaces.core.ContainerReference;
import org.mozartspaces.core.Entry;
import org.mozartspaces.core.aspects.AspectReference;
import org.mozartspaces.core.aspects.AspectResult;
import org.mozartspaces.core.aspects.ContainerAspect;
import org.mozartspaces.core.aspects.ContainerIPoint;
import org.mozartspaces.core.requests.AspectRequest;
import org.mozartspaces.core.requests.CreateContainerRequest;
import org.mozartspaces.core.requests.DeleteEntriesRequest;
import org.mozartspaces.core.requests.DestroyContainerRequest;
import org.mozartspaces.core.requests.LockContainerRequest;
import org.mozartspaces.core.requests.LookupContainerRequest;
import org.mozartspaces.core.requests.ReadEntriesRequest;
import org.mozartspaces.core.requests.RemoveAspectRequest;
import org.mozartspaces.core.requests.TakeEntriesRequest;
import org.mozartspaces.core.requests.TestEntriesRequest;
import org.mozartspaces.core.requests.WriteEntriesRequest;

import sbc.group1.lab1.common.Coatable;

class LabelCoatablesContainerAspect implements ContainerAspect {

    
    public static enum CoatableLabel {
        COATED,
        NOT_COATED, 
        NOT_LABELED;
        public CoordinationData getCoordinationData() {
            return LabelCoordinator.newCoordinationData(
                    this.name(), 
                    CoatableLabel.class.getCanonicalName());
        }
        public Selector getSelector(int count) {
            return LabelCoordinator.newSelector(
                    this.name(), 
                    count, 
                    CoatableLabel.class.getCanonicalName());
        }
        public Selector getSelector() {
            return getSelector(1);
        }
    }
    
    public static LabelCoordinator getCoordinator() {
        return new LabelCoordinator(CoatableLabel.class.getCanonicalName());
    }

    public static Set<ContainerIPoint> getUsedContainerIPoints() {
        Set<ContainerIPoint> ret = new HashSet<ContainerIPoint>();
        ret.add(ContainerIPoint.PRE_WRITE);
        return ret;
    }
    
    @Override
    public AspectResult preWrite(WriteEntriesRequest request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount) {
        ListIterator<Entry> iter = request.getEntries().listIterator();
        while (iter.hasNext()) {
            Entry entry = iter.next();
            iter.remove();
            iter.add(createReplacement(entry));
        }
        return AspectResult.OK;
    }

    private Entry createReplacement(Entry entry) {
        LinkedList<CoordinationData> coordinationData = 
            new LinkedList<CoordinationData>();
        for (CoordinationData data : entry.getCoordinationData()) {
            if (data.getName().equals(CoatableLabel.class.getCanonicalName())) {
            }else {
                coordinationData.add(data);
            }
        }
        if (entry.getValue() instanceof Coatable) {
            Coatable coatable = (Coatable) entry.getValue();
            coordinationData.add(getLabelForCoatable(coatable));
        }else {
            coordinationData.add(
               CoatableLabel.NOT_LABELED.getCoordinationData());
        }
        return new Entry(entry.getValue(),coordinationData);
    }

    private CoordinationData getLabelForCoatable(Coatable coatable) {
        if (coatable.isCoated()) {
            return CoatableLabel.COATED.getCoordinationData();

        }else {
            return CoatableLabel.NOT_COATED.getCoordinationData();
        }
    }
    @Override
    public AspectResult postAddAspect(
            AspectRequest<AspectReference> request, Transaction tx,
            SubTransaction stx, Capi3AspectPort capi3, int executionCount,
            AspectReference aspect) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult postCreateContainer(CreateContainerRequest request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount, ContainerReference container) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult postDelete(DeleteEntriesRequest request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount, List<? extends Serializable> entries) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult postDestroyContainer(
            DestroyContainerRequest request, Transaction tx,
            SubTransaction stx, int executionCount) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult postLockContainer(LockContainerRequest request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult postLookupContainer(LookupContainerRequest request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount, ContainerReference container) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult postRead(ReadEntriesRequest<?> request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount, List<? extends Serializable> entries) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult postRemoveAspect(RemoveAspectRequest request,
            Transaction tx, SubTransaction stx,
            ContainerReference container, Capi3AspectPort capi3,
            int executionCount) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult postTake(TakeEntriesRequest<?> request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount, List<? extends Serializable> entries) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult postTest(TestEntriesRequest request, Transaction tx,
            SubTransaction stx, Capi3AspectPort capi3, int executionCount,
            List<? extends Serializable> entries) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult postWrite(WriteEntriesRequest request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult preAddAspect(AspectRequest<AspectReference> request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult preDelete(DeleteEntriesRequest request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult preDestroyContainer(DestroyContainerRequest request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult preLockContainer(LockContainerRequest request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult preRead(ReadEntriesRequest<?> request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult preRemoveAspect(RemoveAspectRequest request,
            Transaction tx, SubTransaction stx,
            ContainerReference container, Capi3AspectPort capi3,
            int executionCount) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult preTake(TakeEntriesRequest<?> request,
            Transaction tx, SubTransaction stx, Capi3AspectPort capi3,
            int executionCount) {
        return AspectResult.OK;
    }

    @Override
    public AspectResult preTest(TestEntriesRequest request, Transaction tx,
            SubTransaction stx, Capi3AspectPort capi3, int executionCount) {
        return AspectResult.OK;
    }

}
